package midas.mw;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Properties;

import midas.mw.cfg.CfgError;
import midas.mw.cfg.CfgLogging;

/**
 * This standalone middleware application is used to control the MIDAS
 * middleware from its environment. Using it requires that the middleware is 
 * up and running. When 'MwControl' is started it establish a communication 
 * path to the running middleware which continuously waits for input received
 * from 'MwControl' as long as not busy with other activities. The
 * communication path is based on using a node local socket connection using
 * port no. 'ServerSocketNo'. The communication is one direction - from 'MwControl' to
 * middleware, and therefore the middleware is not able to signal the effects of
 * requests received from 'MwControl'.<p>
 * 
 * The requests communicated to the middleware is specified by the 'MwControl' user
 * by specifying a set of space separated arguments at 'MwControl' startup. Which requests
 * the middleware is able to interpret is determined by the middleware functionality.
 * At this time the following 'MwControl' usage is defined:<p><p>
 * 
 * MwControl 'MwCommand'<p><p>
 * 
 * where 'MwCommand' interpreted by the middleware are:<p><p>
 * 
 * 'TERMINATE': The middleeware will terminate after executing the 'mwStop()' method
 * for all running applications and middleware components.<p><p>
 * 
 * START 'class' ['arguments']<p><p>
 * 
 * where 'class' specifies the binary class name (e.g. 'midas.apps.exapp.ExApp' to
 * start the provided example application) for the main class for the component/application
 * to start. 'arguments' are optional arguments that will have component specific
 * meaning if to be used and that will be provides as a set of arguments according to the
 * 'String[] args' parameter specified for the required component provided method 'mwStart()'.<p>
 * 
 * Note also that if the middleware shall be controlled from another application in stead of from
 * OS command level the application may directly use the middleware interface using
 * socket and port 'ServerSocketNo' in stead of starting 'MwControl'.
 */
public class MwControl {
	
	/** Local port number to be used for Socket communication between 'MwControl' and 'MwImpl' classes */
	private int serverSocketPortNo = Integer.parseInt(Common.DEFAULT_SERVER_SOCKET_PORT_NO);
	private String serverSocketIPAddress = Common.DEFAULT_SERVER_SOCKET_IP_ADDRESS;

	public MwControl() {
		configure();
	}
	
	public int send(String data) {
		if (Common.DEBUG) CfgLogging.logEvent(CfgLogging.LOG_MCALL, "MW_Core", CfgLogging.SEV_DEBUG, "MwControl.send()");
		String d = data+"\n";
		Socket socket = null;
		try {
			socket = new Socket(serverSocketIPAddress, serverSocketPortNo);
			OutputStream outStream = socket.getOutputStream();
			outStream.write(d.getBytes());
			outStream.close();
			socket.close();
			socket = null;
		} catch (UnknownHostException e) {
			CfgError.errorReporting(CfgError.ERR_OPER, "MW_Core", CfgError.SEV_ERROR, 
					"MwControl.send(), failed to write socket (UnknownHostException) '"+e.getMessage()+"'", null);
		} catch (IOException e) {
			CfgError.errorReporting(CfgError.ERR_OPER, "MW_Core", CfgError.SEV_ERROR, 
					"MwControl.send(), failed to write socket (IOException) '"+e.getMessage()+"'", null);
		}
		finally {
			try {
				if (socket != null) socket.close();
				socket = null;
			}
			catch (IOException ex) {}				
		}
		
		return 0;
	}

	/**
	 * Perform necessary configuration of the middleware. Configuration parameters are read
	 * from the file defined by the variable 'CONFIGURATION_FILE'.
	 * @return 0: No error; -1:Error exit
	 */
	private int configure() {
		Properties middlewareProperties;

	    /* Loading the properties file
	     */
	    try 
	    {	    	
	    	FileInputStream file = new FileInputStream(Common.CONFIGURATION_FILE);

	    	middlewareProperties = new Properties();
	    	middlewareProperties.load(file);
	    	file.close();
	    	
	    	//Set Server Socket communication port no	 
	    	serverSocketPortNo = Integer.parseInt(middlewareProperties.getProperty("ServerSocketPortNo"));
			CfgLogging.logEvent(CfgLogging.LOG_INFO, "MW_Core", CfgLogging.SEV_INFORMAL, "PROPERTY ServerSocketPortNo = " + serverSocketPortNo);
	    	
			serverSocketIPAddress = middlewareProperties.getProperty("ServerSocketIpAddress", Common.DEFAULT_SERVER_SOCKET_IP_ADDRESS);
			CfgLogging.logEvent(CfgLogging.LOG_INFO, "MW_Core", CfgLogging.SEV_INFORMAL, "PROPERTY ServerSocketIpAddress = " + serverSocketIPAddress);
	    	
			
	    } catch (FileNotFoundException fnfe) {
	    	CfgError.errorReporting(CfgError.ERR_OPER, "MW_Core", CfgError.SEV_ERROR, 
					"configure(). Failed to get the Properties file ' (FileNotFoundException)" + 
					fnfe.getMessage() + "'", null);
	      	return -1;
	    } catch (IOException ioe) {
	    	CfgError.errorReporting(CfgError.ERR_OPER, "MW_Core", CfgError.SEV_ERROR, 
					"configure(). Failed to read the Properties file ' (IOException)" + 
					ioe.getMessage() + "'", null);
	    	return -1;
	    }
	    
	    return 0;
	}

	
	/**
	 * The functionality is to communicate
	 * the provided arguments to the running middleware through some communication
	 * channel, using 'Socket()' at port 'ServerSocketNo'. 
	 * MIDAS middleware will then read the received command, decode it according to
	 * its meaning. The middleware may both be stopped ('TERMINATE') and
	 * applications may be started ('START') specifying application main class name and
	 * optionally the set of arguments. The middleware starts the application
	 * in a separate thread running within the middleware OS process.
	 * 
	 * @param args List of arguments that are serialised and send to middleware
	 */
	public static void main(String[] args) {
		if (Common.DEBUG) CfgLogging.logEvent(CfgLogging.LOG_MCALL, "MW_Core", CfgLogging.SEV_DEBUG, "MwControl.main("+args+")");

		if (args == null || args.length == 0)
			//No arguments specified - do nothing
			return;
		
		//Instantiate class that performs 'send()'
		MwControl as = new MwControl();
		
		//Serialize arguments and send to MIDAS middleware
		int l = args.length;
		String p = "";
		for (int i = 0; i < l; ++i)
			if (i == 0)
				p += args[i];
			else
				p += " "+args[i];

		if (Common.DEBUG) CfgLogging.logEvent(CfgLogging.LOG_MCALL, "MW_Core", CfgLogging.SEV_DEBUG, "MwControl.main(), send to MIDAS middleware '"+p+"'");
		as.send(p);		
	}

}
